﻿Imports Microsoft.Xna.Framework
Imports Microsoft.Xna.Framework.GamerServices

Public MustInherit Class GameScreen
    Inherits Screen
    Implements ICollisionCandidateProvider
    Implements IGameObjectParent

#Region " Fields "
    Private mCamera As Camera3D

    Private mObjects As New List(Of GameObject)
    Private mCharacters As New List(Of MovableObject)
    Private mTerrain As New List(Of ITerrain)
    Private mSkyBox As SkyBox
#End Region ' Fields

#Region " Properties "

    Public Property Camera() As Camera3D
        Get
            Camera = mCamera
        End Get
        Set(ByVal value As Camera3D)
            mCamera = value
        End Set
    End Property

    ''' <summary>
    ''' Immoveabe game objects. These objects will not need to check if they 
    ''' collide with each other as they are static.
    ''' </summary>
    Public ReadOnly Property Objects() As List(Of GameObject) Implements IGameObjectParent.Objects
        Get
            Objects = mObjects
        End Get
    End Property

    ''' <summary>
    ''' Avatars and other moveable game objects.
    ''' </summary>
    Public ReadOnly Property Characters() As List(Of MovableObject)
        Get
            Characters = mCharacters
        End Get
    End Property

    ''' <summary>
    ''' Terrain of the game world
    ''' </summary>
    ''' <remarks>Currently will only hold a single Terrain.</remarks>
    Public ReadOnly Property Terrain() As List(Of ITerrain)
        Get
            Terrain = mTerrain
        End Get
    End Property

    Public Property SkyBox() As SkyBox
        Get
            SkyBox = mSkyBox
        End Get
        Set(ByVal value As SkyBox)
            mSkyBox = value
        End Set
    End Property

    ''' <remarks>
    ''' This will need changing to handle multiple terrain objects.
    ''' Being able to have multiple terrain objects will allow the world's 
    ''' terrain to be split into several models. Then, we can improve 
    ''' performance by only drawing the visible ones.
    ''' </remarks>
    Public ReadOnly Property HeightMapInfo() As HeightMapInfo Implements ICollisionCandidateProvider.HeightMapInfo
        Get
            If mTerrain.Count > 0 AndAlso mTerrain(0).HeightMapInfo IsNot Nothing Then
                HeightMapInfo = Terrain(0).HeightMapInfo
            Else
                HeightMapInfo = Nothing
            End If
        End Get
    End Property

#End Region

    ''' <summary>
    ''' This is called after all updates but before any acutal drawing.
    ''' </summary>
    Public Overrides Sub UpdatePresentation(ByVal elapsedSeconds As Single)
        MyBase.UpdatePresentation(elapsedSeconds)
        If mCamera IsNot Nothing Then mCamera.Update(elapsedSeconds)
    End Sub

#Region " Initialization "
    Public Sub New(ByVal GameManager As GameManager)
        MyBase.New(GameManager)
        mCamera = New Camera3D(GameManager, Me)
    End Sub

    Public Overrides Sub Initialize()
        For Each mObj As MovableObject In mCharacters
            mObj.Initialize()
        Next
        For Each gObj As GameObject In mObjects
            gObj.Initialize()
        Next
        For Each t As ITerrain In mTerrain
            t.Initialize()
        Next
        mSkyBox = New SkyBox(GameManager)
        mSkyBox.Initialize()
    End Sub

    Public Overrides Sub LoadContent()
        For Each gObj As GameObject In mCharacters
            gObj.LoadContent()
        Next
        For Each gObj As GameObject In mObjects
            gObj.LoadContent()
        Next
        For Each t As ITerrain In mTerrain
            t.LoadContent()
        Next

        mSkyBox.LoadContent()
    End Sub

    Public Overrides Sub UnloadContent()
        For Each gObj As GameObject In mCharacters
            gObj.UnloadContent()
        Next
        For Each gObj As GameObject In mObjects
            gObj.UnloadContent()
        Next
        For Each t As ITerrain In mTerrain
            t.UnloadContent()
        Next

        mSkyBox.UnloadContent()
    End Sub
#End Region

#Region " Update and Draw "

    Public Overrides Sub Update(ByVal elapsedSeconds As Single)
        For Each mObj As MovableObject In mCharacters
            mObj.Update(elapsedSeconds, Me)
        Next
        mSkyBox.Update(elapsedSeconds)
    End Sub

    Public Function GetCollisionCandidates(ByVal mObj As MovableObject) As List(Of GameObject) Implements ICollisionCandidateProvider.GetCollisionCandidates
        GetCollisionCandidates = New List(Of GameObject)
        For Each candidate As MovableObject In Characters
            If candidate IsNot mObj AndAlso mObj.BoundingSphere.Intersects(candidate.BoundingSphere) Then
                GetCollisionCandidates.Add(candidate)
            End If
        Next
        For Each candidate As GameObject In Objects
            GetCollisionCandidates.AddRange(candidate.GetCollisionCandidates(mObj))
        Next
    End Function

    Public Overrides Sub HandleInput(ByVal input As IGamePadInputManager)
        For Each mObj As MovableObject In mCharacters
            mObj.HandleInput(input)
        Next
    End Sub

    Public Overrides Sub Draw(ByVal elapsedSeconds As Single)
        For Each mObj As MovableObject In mCharacters
            If Camera.BoundingFrustum.Intersects(mObj.BoundingSphere) Then
                mObj.Draw(elapsedSeconds, Camera)
            End If
        Next
        For Each gObj As GameObject In mObjects
            ' TODO - remove this line
            'If Camera.BoundingFrustum.Intersects(gObj.BoundingSphere) Then _
            gObj.Draw(elapsedSeconds, Camera)
        Next
        For Each t As ITerrain In mTerrain
            If Camera.BoundingFrustum.Intersects(t.BoundingSphere) Then
                t.Draw(elapsedSeconds, Camera)
            End If
        Next
        mSkyBox.Draw(elapsedSeconds, Camera)
    End Sub


#End Region ' Update and Draw

    ''' <summary>
    ''' Dummy Method to satisfy interface
    ''' </summary>
    Private Sub InvalidateMatrices() Implements IGameObjectParent.InvalidateMatrices
    End Sub

End Class
